﻿using System.Collections.Generic;

namespace Shell.KnowledgeBase
{
    public static class UnificationModule
    {
        public static bool Unify(this Term t1, Term t2, BindingContext bindingContext)
        {
            if (t1 is Variable)
            {
                return ((Variable) t1).Unify(t2, bindingContext);
            }
            else if (t2 is Variable)
            {
                return ((Variable)t2).Unify(t1, bindingContext);
            }
            else if (t1 is Statement && t2 is Statement)
            {
                return UnifyStatements(
                    (Statement) t1,
                    (Statement) t2,
                    bindingContext);
            }
            else
            {
                return t1.Equals(t2);
            }
        }

        public static bool UnifyStatements(Statement first, Statement second, BindingContext bindingContext)
        {
            return UnifyStatements(first, second, 0, bindingContext);
        }

        public static bool UnifyStatements(Statement first, Statement second, int startIndex, BindingContext bindingContext)
        {
            if ((first.Length - startIndex) < second.Length)
            {
                return false;
            }

            var length = second.Length;

            for (var i = 0; i < length; i++)
            {
                if (!first[startIndex + i].Unify(second[i], bindingContext))
                {
                    return false;
                }
            }

            return true;
        }

        public class UnificationComparer : IEqualityComparer<Term>
        {
            public bool Equals(Term x, Term y)
            {
                return x.Unify(y, new BindingContext());
            }

            public int GetHashCode(Term obj)
            {
                return obj.GetHashCode();
            }
        }

        public static IEnumerable<BindingContext> UnifyStatementsEx(Statement a1, Statement f1, BindingContext bindingContext)
        {
            var result = bindingContext.Derive();
            if (UnifyStatements(a1, f1, result))
            {
                yield return result;
            }
        }
    }
}
